package com.zyz.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Aspect
@Component
public class LoggingAspect {

    // 定义切入点：匹配 com.zyz.service 包及其子包下的所有方法
    @Pointcut("execution(* com.zyz.service..*(..))")
    public void serviceMethods() {}

    // 前置通知：目标方法执行前执行，打印方法名和参数
    @Before("serviceMethods()")
    public void beforeMethod(JoinPoint joinPoint) {
        System.out.println("调用方法：" + joinPoint.getSignature().getName() + "，参数：" + Arrays.toString(joinPoint.getArgs()));
    }

    // 后置通知：目标方法执行后执行（无论方法是正常返回还是抛异常），打印方法执行完成
    @After("serviceMethods()")
    public void afterMethod(JoinPoint joinPoint) {
        System.out.println("方法执行完成：" + joinPoint.getSignature().getName());
    }

    // 返回通知：目标方法正常返回时执行，打印返回结果
    @AfterReturning(pointcut = "serviceMethods()", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        System.out.println("方法 " + joinPoint.getSignature().getName() + " 返回结果：" + result);
    }

    /**
     * 异常通知（After Throwing Advice）
     * 当目标方法执行抛出异常时触发此通知。
     *
     * 参数说明：
     * - JoinPoint joinPoint：代表连接点的信息，可以获取方法签名等信息。
     * - Throwable ex：被抛出的异常对象。
     *
     * 工作流程：
     * 1. 当匹配的 service 方法执行时，如果该方法执行过程中抛出了异常，
     *    Spring AOP 会捕获该异常，并调用本方法进行通知。
     * 2. 该通知方法通过参数 ex 获取异常信息，然后打印异常消息。
     * 3. 该异常通知不会“吞掉”异常，异常仍会向上抛出，可以被调用方捕获。
     */
    @AfterThrowing(pointcut = "serviceMethods()", throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint, Throwable ex) {
        System.out.println("方法 " + joinPoint.getSignature().getName() + " 抛出异常：" + ex.getMessage());
    }
}
